home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / comm / bbs / s342q07.lha / netmisc.c < prev    next >
C/C++ Source or Header  |  1995-08-08  |  65KB  |  2,505 lines

  1. /*
  2. *       netmisc.c
  3. *
  4. * Networking functions of miscellaneous type.
  5. */
  6. /*
  7. *       history
  8. *
  9. * 91Aug17 HAW  New comment style.
  10. * 86Aug20 HAW  History not maintained due to space problems.
  11. */
  12. #include "ctdl.h"
  13. /*
  14. *       contents
  15. *
  16. */
  17. /* #define NET_DEBUG 1  */
  18. /*
  19. *   External variable declarations in NET.C
  20. */
  21.  
  22.  
  23.  
  24. char    *SR_Sent;
  25. char    ErrBuf[100];    /* General buffer for error messages */
  26. label   HomeId;
  27. int   AnyIndex = 0;  /* tracks who to call between net sessions */
  28. FILE    *netLog, *netMisc, *netMsg;
  29. static char     UsedNetMsg;
  30. char    *nMsgTemplate = "netMsg.$$$";
  31. char    logNetResults = FALSE;
  32. char    inNet = NON_NET;
  33. AN_UNSIGNED     RecBuf[SECTSIZE + 5];
  34. int   callSlot;
  35. label   normed, callerName, callerId;
  36. logBuffer       *lBuf;
  37. int   PriorityMail = 0;
  38. char    *pollCall;
  39. int   LD_Delay = 60;
  40. static char *SupportedBauds[] =
  41.   {
  42.   "300", "3/12", "3/24", "3/48", "3/96", "3/14.4", "3/19.2", "3/38.4", "3/57.6"
  43.  
  44.   };
  45. /*
  46. * UntilNetSessions
  47. *
  48. * This is used to maintain a list of Until-Done net sessions as requested by
  49. * the sysop.  Each element contains information concerning which member net
  50. * is involved (only one can be specified) and how long the session should
  51. * last.
  52. */
  53. void ExplainNeed(int i, MULTI_NET_DATA x);
  54. void freeUNS();
  55. SListBase UntilNetSessions =
  56.   {
  57.   NULL, ChkTwoNumbers, NULL, freeUNS, NULL
  58.  
  59.   };
  60. /*
  61. *   External variable definitions for NET.C
  62. */
  63. extern CONFIG    cfg;   /* Lots an lots of variables    */
  64. extern NetBuffer netTemp;
  65. extern logBuffer logBuf;  /* Person buffer    */
  66. extern logBuffer logTmp;  /* Person buffer    */
  67. extern aRoom     roomBuf; /* Room buffer      */
  68. extern rTable    *roomTab;
  69. extern MessageBuffer   msgBuf;
  70. extern MessageBuffer   tempMess;
  71. extern NetBuffer netBuf;
  72. extern NetTable  *netTab;
  73. extern int       thisNet;
  74. extern char      onConsole;
  75. extern char      loggedIn;  /* Is we logged in?   */
  76. extern char      outFlag; /* Output flag      */
  77. extern char      haveCarrier; /* Do we still got carrier?     */
  78. extern char      modStat; /* Needed so we don't die       */
  79. extern char      WCError;
  80. extern int       thisRoom;
  81. extern int       thisLog;
  82. extern char      *confirm;
  83. extern char      heldMess;
  84. extern char      netDebug;
  85. extern char      *AssignAddress;
  86. extern char      remoteSysop;
  87. extern char     *DomainFlags;
  88. /*
  89. * called_stabilize()
  90. *
  91. * This function attempts to stabilize communication on the receiver end.
  92. */
  93. char called_stabilize()
  94.   {
  95.   char retVal;
  96.   retVal = getNetBaud();  /* has to handle stroll, too. */
  97.   if (!gotCarrier())
  98.     {
  99.     killConnection();
  100.     retVal = FALSE;
  101.  
  102.     }
  103.   return retVal;
  104.  
  105.   }
  106. static int table[2][3] =
  107.   {
  108.     { 7, 13, 69 },
  109.     {68, 79, 35}
  110.  
  111.   };
  112. /*
  113. * check_for_init()
  114. *
  115. * This function looks for the networking initialization sequence.
  116. */
  117. char check_for_init(char mode)
  118.   {
  119.   int index;
  120.   int count, timeOut;
  121.   AN_UNSIGNED thisVal, lastVal;
  122.   index = (inNet == STROLL_CALL) ? 1 : 0;
  123.   lastVal = (mode) ? table[index][0] : 0;
  124.   timeOut = (INTERVALS / 2) * (25);
  125.   for (count = 0; count < timeOut; count++)
  126.     {
  127.     if (MIReady())
  128.       {
  129.       thisVal = inp();
  130.       if (cfg.BoolFlags.debug) splitF(netLog, "CFI:%d(%d/%d/%d) ",count,thisVal, lastVal,index);
  131.       if (thisVal == table[index][0])
  132.       lastVal = table[index][0];
  133.       else if (thisVal == table[index][1])
  134.         {
  135.         if (lastVal == table[index][0]) lastVal = table[index][1];
  136.         else  lastVal = 0;
  137.  
  138.         }
  139.       else if (thisVal == table[index][2])
  140.         {
  141.         if (lastVal == table[index][1])
  142.           {
  143.           lastVal = AckStabilize(index);
  144.           if (lastVal == ACK) return TRUE;
  145.           else if (lastVal == table[index][2])
  146.           return(char) (AckStabilize(index) == ACK);
  147.           else if (lastVal != table[index][0] &&
  148.           lastVal != table[index][1])
  149.           return (char)FALSE;
  150.  
  151.           }
  152.  
  153.         }
  154.  
  155.       }
  156.     else pause(2);
  157.  
  158.     }
  159.   return FALSE;
  160.  
  161.   }
  162. /*
  163. * AckStabilize()
  164. *
  165. * This function tries to stabilize with net caller.
  166. */
  167. int AckStabilize(int index)
  168.   {
  169.   int temp;
  170.   outMod(~(table[index][0]));
  171.   outMod(~(table[index][1]));
  172.   outMod(~(table[index][2]));
  173.   temp = receive(1);
  174.   if (cfg.BoolFlags.debug) splitF(netLog, "AckStabilize=%d\n",temp);
  175.   return temp;
  176.  
  177.   }
  178. /*
  179. * AddNetMsgs()
  180. *
  181. * This function integrates messages into the data base.  Options include
  182. * adding the net area or not to the filename and specifying the processing
  183. * function rather than being stuck with a standard processing function.
  184. * Usually the processing function will integrate messages into the message
  185. * data base, although it may do negative mail checking instead.
  186. */
  187. int AddNetMsgs(char *base, void (*procFn)(void), char zap, int roomNo,
  188. char AddNetArea)
  189.   {
  190.   char tempNm[80];
  191.   int count = 0;
  192.   extern char *READ_ANY;
  193.   if (AddNetArea)
  194.   makeSysName(tempNm, base, &cfg.netArea);
  195.   else
  196.   strCpy(tempNm, base);
  197.   if ((netMisc = safeopen(tempNm, READ_ANY)) == NULL)
  198.     {
  199.     return ERROR;
  200.  
  201.     }
  202.   getRoom(roomNo);
  203.   /* If reading for mail room, prepare a log buffer. */
  204.   if (roomNo == MAILROOM)
  205.   lBuf = &logTmp;
  206.   else
  207.   lBuf = NULL;
  208.   while (getMessage(getNetChar, TRUE, TRUE, TRUE))
  209.     {
  210.     count++;
  211.     if (strCmpU(cfg.nodeId + cfg.codeBuf, msgBuf.mborig) != SAMESTRING)
  212.     (*procFn)();
  213.  
  214.     }
  215.   fclose(netMisc);
  216.   if (zap == 1) unlink(tempNm);
  217.   else if (zap == 2 && count != 0) unlink(tempNm);
  218.   return count;
  219.  
  220.   }
  221. /*
  222. * getNetChar()
  223. *
  224. * This function gets a character from a network temporary file.  The file
  225. * should have been opened elsewhere.
  226. */
  227. int getNetChar()
  228.   {
  229.   int c;
  230.   c = fgetc(netMisc);
  231.   if (c == EOF) return -1;
  232.   return c;
  233.  
  234.   }
  235. /*
  236. * inMail()
  237. *
  238. * This function integrates a message into the message database.  It includes
  239. * recognizing bangmail, vortex activation, and bad word scanning.
  240. */
  241. void inMail()
  242.   {
  243.   extern SListBase BadPeople;
  244.   extern SListBase BadWords;
  245.   /* do we need any code here? */
  246.   if (thisRoom == MAILROOM &&
  247.   (strchr(msgBuf.mbto, '!') != NULL ||
  248.   strchr(msgBuf.mbauth, '!') != NULL))
  249.   MakeRouted();   /* Route.C */
  250.   else if (NotVortex())
  251.     {
  252.     if (cfg.BoolFlags.NetScanBad)
  253.       {
  254.       if (thisRoom != MAILROOM && SearchList(&BadWords, msgBuf.mbtext) != NULL)
  255.         {
  256.         extern char BadMessages[];
  257.  
  258.         DiscardMessage( strlen(BadMessages)? BadMessages : "discard");
  259.  
  260.         sPrintf(msgBuf.mbtext,
  261.         "Net message from %s @%s in %s discarded for decency reasons.",
  262.         msgBuf.mbauth, msgBuf.mboname,
  263.         (roomExists(msgBuf.mbroom)) ?
  264.         formRoom(roomExists(msgBuf.mbroom), FALSE, FALSE) :
  265.         msgBuf.mbroom);
  266.         netResult(msgBuf.mbtext);
  267.         return;
  268.  
  269.         }
  270.       if (thisRoom != MAILROOM && SearchList(&BadPeople, &msgBuf) != NULL)
  271.         {
  272.         extern char BadMessages[];
  273.  
  274.         DiscardMessage( strlen(BadMessages)? BadMessages : "discard");
  275.  
  276.         sPrintf(msgBuf.mbtext,
  277.         "Net message from %s @%s in %s discarded By Sysop Option.",
  278.         msgBuf.mbauth, msgBuf.mboname,
  279.         (roomExists(msgBuf.mbroom)) ?
  280.         formRoom(roomExists(msgBuf.mbroom), FALSE, FALSE) :
  281.         msgBuf.mbroom);
  282.         netResult(msgBuf.mbtext);
  283.         return;
  284.  
  285.         }
  286.  
  287.       }
  288.     if (AssignAddress != NULL)
  289.     strCpy(msgBuf.mbaddr, AssignAddress);
  290.     putMessage(&logBuf);
  291.  
  292.     }
  293.   else DiscardMessage("discard");
  294.  
  295.   }
  296. static int GoodCount, BadCount;
  297. /*
  298. * inRouteMail()
  299. *
  300. * This function handles incoming route mail.
  301. */
  302. void inRouteMail()
  303.   {
  304.   label oname, domain;
  305.   if (RecipientAvail())
  306.     {
  307.     inMail();
  308.  
  309.     }
  310.   if (BadCount)
  311.     {
  312.     sPrintf(lbyte(tempMess.mbtext), " on %s _ %s was undeliverable.",
  313.     cfg.nodeName + cfg.codeBuf,
  314.     cfg.codeBuf + cfg.nodeDomain);
  315.     strCpy(tempMess.mbto, msgBuf.mbauth);
  316.     strCpy(oname, msgBuf.mboname);
  317.     strCpy(domain, msgBuf.mbdomain);
  318.     strCpy(tempMess.mbauth, "Citadel");
  319.     strCpy(tempMess.mbroom, "Mail");
  320.     strCpy(tempMess.mbtime, Current_Time());
  321.     strCpy(tempMess.mbdate, formDate());
  322.     sPrintf(tempMess.mbId, "%lu", cfg.newest++ + 1);
  323.     ZeroMsgBuffer(&msgBuf);
  324.     MoveMsgBuffer(&msgBuf, &tempMess);
  325.     netMailOut(TRUE, UseNetAlias(oname, FALSE), domain, FALSE, -1);
  326.  
  327.     }
  328.  
  329.   }
  330. /*
  331. * RecipientAvail()
  332. *
  333. * This function checks to see if recipient is here.  This includes override
  334. * handling.
  335. */
  336. char RecipientAvail()
  337.   {
  338.   void RecAvWork(char *);
  339.   GoodCount = BadCount = 0;
  340.   if (msgBuf.mbdomain[0])
  341.     {
  342.     if (!HasOverrides(&msgBuf))
  343.       {
  344.       RecAvWork(msgBuf.mbto);
  345.  
  346.       }
  347.     else
  348.       {
  349.       RunList(&msgBuf.mbOverride, RecAvWork);
  350.  
  351.       }
  352.     return (char)GoodCount;
  353.  
  354.     }
  355.   return TRUE;
  356.  
  357.   }
  358. /*
  359. * RecAvWork()
  360. *
  361. * This function does the real work of RecipientAvailable() - split out to
  362. * better handle other recipients.
  363. */
  364. void RecAvWork(char *name)
  365.   {
  366.   if (PersonExists(name) == ERROR &&
  367.   strCmpU(msgBuf.mbauth, "Citadel") != SAMESTRING)
  368.     {
  369.     BadCount++;
  370.     if( logNetResults )splitF(netLog, "No recipient: %s\n", name);
  371.     if (BadCount == 1)
  372.     sPrintf(tempMess.mbtext, "Your message to %s", name);
  373.     else
  374.     sPrintf(lbyte(tempMess.mbtext), ", %s", name);
  375.  
  376.     }
  377.   else if (PersonExists(name) != ERROR ||
  378.   strCmpU(msgBuf.mbauth, "Citadel") != SAMESTRING)
  379.   GoodCount++;
  380.  
  381.   }
  382. /*
  383. * DiscardMessage()
  384. *
  385. * This function prints a message to a discard file.
  386. */
  387. void DiscardMessage(char *filename)
  388.   {
  389.   extern int outPut;
  390.   extern FILE *upfd;
  391.   extern char *APPEND_TEXT;
  392.   if (redirect(filename))
  393.     {
  394.     mPrintf("%s (%s)", formHeader(), msgBuf.mbsrcId);
  395.     doCR();
  396.     mFormat(msgBuf.mbtext);
  397.     doCR();
  398.     doCR();
  399.     undirect();
  400.  
  401.     }
  402.  
  403.   }
  404. char *kip = NULL;
  405. /*
  406. * netController()
  407. *
  408. * This is the main manager of a network session.  It is responsible for
  409. * scheduling calls, noticing incoming calls, exiting network sessions due
  410. * to timeouts or other events, forming error reports for the Aide> room,
  411. * etc.
  412. */
  413. #define unSetPoll()     free(pollCall)
  414. void mTrPrintf(char *,...);
  415. void netController(int NetStart, int NetLength, MULTI_NET_DATA whichNets,
  416. char mode, UNS_16 flags)
  417.   {
  418.   int x;
  419.   int searcher = 0, start, first;
  420.   SYS_FILE AideMsg;
  421.   long waitTime, InterCallDelay;
  422.   extern char *WRITE_TEXT, *READ_TEXT, *APPEND_TEXT;
  423.   extern void (*NetPrintTarget)();
  424.   SpecialMessage("Status:Network Controller");
  425.   if (cfg.BoolFlags.debug)
  426.      splitF(netLog, "netController(%d,%d, %ld, %d,%d)\n", NetStart, NetLength,whichNets, (int)mode, flags);
  427.   if (loggedIn) /* should only happen on mistake by sysop */
  428.   terminate( /* hangUp == */ TRUE, TRUE);
  429.   NetPrintTarget = mTrPrintf;
  430.   outFlag = OUTOK;    /* for discarding messages correctly */
  431.   inNet = mode;
  432.   setPoll();
  433.   switch (mode)
  434.     {
  435.     case ANYTIME_NET:
  436.     case UNTIL_NET:
  437.     if (!AnyCallsNeeded(whichNets))
  438.       {
  439.       inNet = NON_NET;
  440.       unSetPoll();
  441.       return;
  442.  
  443.       }
  444.     searcher = AnyIndex;    /* so we don't always start at front */
  445.     break;
  446.     case ANY_CALL:
  447.     while (MIReady()) inp();
  448.     break;
  449.  
  450.     }
  451.   InterCallDelay = (!(flags & LEISURELY)) ? 2l : 15l;
  452.   SR_Sent = (char *) GetDynamic(SHARED_ROOMS);
  453.   if (logNetResults)
  454.     {
  455.     makeSysName(AideMsg, "netlog.sys", &cfg.netArea);
  456.     if ((netLog = safeopen(AideMsg, APPEND_TEXT)) == NULL)
  457.     netResult("Couldn't open netLog");
  458.  
  459.     }
  460.   else  netLog = NULL;
  461.   loggedIn = FALSE;     /* Let's be VERY sure.  */
  462.   thisLog = -1;
  463.   splitF(netLog, "\nNetwork Session %s @ %s\n", formDate(), Current_Time());
  464.   SpecialMessage("Network Session");
  465.   logMessage(INTO_NET, "", 0);
  466.   modStat = haveCarrier = FALSE;
  467.   setTime(NetStart, NetLength);
  468.   makeSysName(AideMsg, nMsgTemplate, &cfg.netArea);
  469.   if ((netMsg = safeopen(AideMsg, WRITE_TEXT)) == NULL)
  470.   splitF(netLog, "WARNING: Can't open %s!!!!\n", AideMsg);
  471.   UsedNetMsg = FALSE;
  472.   x = timeLeft();
  473.   do
  474.     {
  475.     /* force at least one time through loop */
  476.     waitTime = (cfg.catChar % 5) + 1;
  477.     while (waitTime > minimum(5, (x/2) ) ) waitTime /= 2;
  478.     if (flags & LEISURELY)
  479.     for (startTimer(WORK_TIMER);
  480.     chkTimeSince(WORK_TIMER) < (waitTime * 60) &&
  481.     !KBReady();)
  482.       {
  483.       if (gotCarrier()) break;
  484.       else BeNice(NET_PAUSE);
  485.  
  486.       }
  487.     /* This will break us out of a network session if ESC is hit */
  488.     if (KBReady())
  489.     if (getCh() == SPECIAL) break;
  490.     /*
  491.     * In case someone calls while we're doing after-call processing.
  492.     */
  493.     while (gotCarrier())
  494.       {
  495.       modStat = haveCarrier = TRUE;
  496.       called();
  497.       /* CacheMessages(ALL_NETS, TRUE); */
  498.  
  499.       }
  500.     /* ok, make calls */
  501.     if (cfg.netSize != 0)
  502.       {
  503.       start = searcher;
  504.       do
  505.         {
  506.         if (needToCall(searcher, whichNets))
  507.           {
  508.           ExplainNeed(searcher, whichNets);
  509.           if (!HasPriorityMail(searcher))
  510.           CacheSystem(searcher, FALSE);
  511.           if (callOut(searcher))
  512.             {
  513.             caller();
  514.             if( logNetResults )splitF(netLog, "(%s)\n", Current_Time());
  515.             if (kip != NULL && netBuf.baudCode >= B_5)
  516.               {
  517.               moPuts(kip);
  518.               outMod('\r');
  519.               if( netDebug )splitF(netLog, "debug from modem:\n");
  520.               for (startTimer(WORK_TIMER); chkTimeSince(WORK_TIMER) < 5l || MIReady();)
  521.               splitF(netLog, "%c", inp());
  522.  
  523.               }
  524.             /* CacheMessages(ALL_NETS, TRUE); */
  525.  
  526.             }
  527.           for (startTimer(WORK_TIMER); !gotCarrier() &&
  528.           chkTimeSince(WORK_TIMER) < InterCallDelay;)
  529.           ;
  530.           while (gotCarrier())
  531.             {
  532.             modStat = haveCarrier = TRUE;
  533.             called();
  534.  
  535.             }
  536.           if (whichNets == PRIORITY_MAIL)
  537.             {
  538.             getNet(thisNet, &netBuf);
  539.             netBuf.MemberNets &= ~(PRIORITY_MAIL);
  540.             putNet(thisNet, &netBuf);
  541.  
  542.             }
  543.  
  544.           }
  545.         searcher = (searcher + 1) % cfg.netSize;
  546.         if (mode == ANYTIME_NET && timeLeft() < 0 &&
  547.         whichNets != PRIORITY_MAIL)
  548.         break;      /* maintain discipline */
  549.  
  550.         }
  551.       while (!KBReady() && searcher != start);
  552.  
  553.       }
  554.     if (mode == ANYTIME_NET || mode == UNTIL_NET)
  555.       {
  556.       if (!AnyCallsNeeded(whichNets)) break;
  557.  
  558.       }
  559.  
  560.     }
  561.   while ((x = timeLeft()) > 0);
  562.   splitF(netLog, "\nOut of Networking Mode (%s)\n", Current_Time());
  563.   for (x = 0; x < cfg.netSize; x++)
  564.   if (netTab[x].ntMemberNets & PRIORITY_MAIL)
  565.     {
  566.     getNet(x, &netBuf);
  567.     netBuf.MemberNets &= ~(PRIORITY_MAIL);
  568.     putNet(x, &netBuf);
  569.  
  570.     }
  571.   if (flags & REPORT_FAILURE)
  572.     {
  573.     if (AnyCallsNeeded(whichNets))
  574.       {
  575.       sPrintf(msgBuf.mbtext,
  576.       "The following systems could not be reached: ");
  577.       for (searcher = 0, first = 1; searcher < cfg.netSize; searcher++)
  578.       if (needToCall(searcher, whichNets))
  579.         {
  580.         if (!first) strCat(msgBuf.mbtext,", ");
  581.         first = FALSE;
  582.         getNet(searcher, &netBuf);
  583.         strCat(msgBuf.mbtext, netBuf.netName);
  584.  
  585.         }
  586.       strCat(msgBuf.mbtext, ".");
  587.       netResult(msgBuf.mbtext);
  588.  
  589.       }
  590.  
  591.     }
  592.   if (inNet == ANYTIME_NET)
  593.     {
  594.     AnyIndex = searcher;    /* so we can start from here later */
  595.  
  596.     }
  597.   fclose(netMsg);
  598.   netMsg = NULL;
  599.   /* Make the error and status messages generated into an Aide> msg */
  600.   makeSysName(AideMsg, nMsgTemplate, &cfg.netArea);
  601.   if (UsedNetMsg)
  602.     {
  603.     ZeroMsgBuffer(&msgBuf);
  604.     if (access(AideMsg, 4) == -1)
  605.       {
  606.       sPrintf(msgBuf.mbtext, "Where did '%s' go???", AideMsg);
  607.       aideMessage("Net Aide", FALSE);
  608.  
  609.       }
  610.     else
  611.       {
  612.       ingestFile(AideMsg, &msgBuf);
  613.       aideMessage("Net Aide", FALSE);
  614.  
  615.       }
  616.  
  617.     }
  618.   unlink(AideMsg);
  619.   modStat = haveCarrier = FALSE;
  620.   inNet = NON_NET;
  621.   if (logNetResults)
  622.     {
  623.     fclose(netLog);
  624.     netLog = NULL;
  625.  
  626.     }
  627.   unSetPoll();
  628.   ITL_DeInit();
  629.   free(SR_Sent);
  630.   logMessage(OUTOF_NET, "", 0);
  631.   startTimer(NEXT_ANYNET);      /* anytime net timer */
  632.   getRoom(LOBBY);
  633.  
  634.   }
  635. static int RunUntil;
  636. /*
  637. * setTime()
  638. *
  639. * This function sets up some global variables for the networker.
  640. */
  641. void setTime(int NetStart, int NetLength)
  642.   {
  643.   int yr, hr, mins, dy, temp;
  644.   char *mn;
  645.   startTimer(NET_SESSION);
  646.   if (NetLength == 0)
  647.   RunUntil = 0;
  648.   else
  649.     {
  650.     getCdate(&yr, &mn, &dy, &hr, &mins);
  651.     temp = (hr * 60) + mins;
  652.     RunUntil = 60 * (NetLength - abs(temp - NetStart));
  653.  
  654.     }
  655.  
  656.   }
  657. /*
  658. * timeLeft()
  659. *
  660. * This function does a rough estimate of how much time left and returns it.
  661. */
  662. int timeLeft()
  663.   {
  664.   int elapsed;
  665.   elapsed = chkTimeSince(NET_SESSION);
  666.   if (elapsed > RunUntil) return 0;
  667.   return (((RunUntil - elapsed) / 60) + 1);
  668.  
  669.   }
  670. /*
  671. * callOut()
  672. *
  673. * This function attempts to call some other system.
  674. */
  675. char callOut(int i)
  676.   {
  677.   getNet(callSlot = i, &netBuf);
  678.   if( logNetResults )splitF(netLog, "Calling %s @ %s (%s): ",
  679.   netBuf.netName, netBuf.netId, Current_Time());
  680.   strCpy(normed, netBuf.netId);   /* Cosmetics */
  681.   strCpy(callerId, netBuf.netId);
  682.   strCpy(callerName, netBuf.netName);
  683.   if (makeCall(TRUE, NO_MENU)) return modStat = haveCarrier = TRUE;
  684.   killConnection();   /* Take SmartModem out of call mode   */
  685.   if( logNetResults )splitF(netLog, "No luck.\n");
  686.   return FALSE;
  687.  
  688.   }
  689. /*
  690. * moPuts()
  691. *
  692. * This function puts a string out to modem without carr check.
  693. */
  694. void moPuts(char *s)
  695.   {
  696.   while (*s)
  697.     {
  698.     pause(5);
  699.     if (cfg.BoolFlags.debug) mputChar(*s);
  700.     outMod(*s++);
  701.  
  702.     }
  703.  
  704.   }
  705. /*
  706. * netMessage()
  707. *
  708. * This function will send message via net.  This is a userland function.
  709. */
  710. int netMessage(int uploading)
  711.   {
  712.   if (!NetValidate(TRUE)) return FALSE;
  713.   ZeroMsgBuffer(&msgBuf);
  714.   if (!netInfo(TRUE)) return FALSE;
  715.   return procMessage(uploading, FALSE);
  716.  
  717.   }
  718. /*
  719. * writeNet()
  720. *
  721. * This function writes nodes on the net to the screen.  Options include
  722. * showing only local systems and with or without their ids.
  723. */
  724. void writeNet(char idsAlso, char LocalOnly)
  725.   {
  726.   int rover, count = 0, len;
  727.   int i;
  728.   outFlag = OUTOK;
  729.   mPrintf("Systems on the net:\n ");
  730.   doCR();
  731.   for (rover = 0; outFlag != OUTSKIP && rover < cfg.netSize; rover++)
  732.     {
  733.     if (netTab[rover].ntflags.in_use &&
  734.     (!LocalOnly || netTab[rover].ntflags.local))
  735.       {
  736.       getNet(rover, &netBuf);
  737.       if ((idsAlso || netBuf.MemberNets & ALL_NETS))
  738.         {
  739.         /* mPrintf("%-22s", netBuf.netName); */
  740.         mPrintf("%s", netBuf.netName);
  741.         if (idsAlso)
  742.           {
  743.           #ifdef TURBO_C_VSPRINTF_BUG
  744.           SpaceBug(22 - strLen(netBuf.netName));   /* EEEESH */
  745.           mPrintf("%-22s%-16s%-8s", netBuf.netId,
  746.           (needToCall(rover, ALL_NETS)) ? "<need to call>" : "",
  747.           SupportedBauds[netBuf.baudCode]);
  748.           #else
  749.           mPrintf("%*c%-22s%-16s%-8s", 22 - strLen(netBuf.netName),
  750.           ' ', netBuf.netId,
  751.           (needToCall(rover, ALL_NETS)) ? "<need to call>" : "",
  752.           SupportedBauds[netBuf.baudCode]);
  753.           #endif
  754.           if (netBuf.nbflags.OtherNet) mPrintf("O");
  755.           else if (!(netBuf.MemberNets & ALL_NETS))
  756.           mPrintf("d");
  757.           if (netBuf.nbflags.MassTransfer)
  758.           mPrintf("F");
  759.           mPrintf(" M:");
  760.           for (i = 0; i < 32; i++)
  761.             {
  762.             if ((1l << i) & netBuf.MemberNets) mPrintf("%d ", i + 1);
  763.             };
  764.           doCR();
  765.  
  766.           }
  767.         else
  768.           {
  769.           if (strLen(netBuf.nbShort) != 0)
  770.             {
  771.             mPrintf(" (%s)", netBuf.nbShort);
  772.             len = strLen(netBuf.nbShort) + 3;
  773.  
  774.             }
  775.           else len = 0;
  776.           /* mPrintf(", "); */
  777.           if (++count % 3 == 0)
  778.             {
  779.             count = 0;
  780.             doCR();
  781.  
  782.             }
  783.           else
  784.             {
  785.             #ifdef TURBO_C_VSPRINTF_BUG
  786.             SpaceBug(28 - (len + strLen(netBuf.netName)));   /* EEEESH */
  787.             #else
  788.             mPrintf("%*c", 28 - (len + strLen(netBuf.netName)), ' ');
  789.             #endif
  790.  
  791.             }
  792.  
  793.           }
  794.  
  795.         }
  796.  
  797.       }
  798.  
  799.     }
  800.   if (!idsAlso)
  801.   WriteDomainContents();
  802.  
  803.   }
  804. /*
  805. * netStuff()
  806. *
  807. * This function handles main net menu.
  808. */
  809. void netStuff()
  810.   {
  811.   extern char *who_str;
  812.   extern char ForceNet;
  813.   TwoNumbers  tmp;
  814.   char  work[50];
  815.   label       who;
  816.   int   logNo;
  817.   MenuId  id, id2;
  818.   long  Redials, duration;
  819.   char *Net_Prompt = "\nNet Menu\n ";
  820.   char  *NetMiscOpts[] =
  821.     {
  822.     "A(dd node to netlist) ", "C(redit setting)               ", "D(ial system)\n",
  823.     "E(dit a node)         ", "I(nitiate Anytime Net Session) ", "L(ocal list)\n",
  824.     "N(et privileges)      ", "P(riority Mail)                ", "R(equest File)\n",
  825.     "S(end File)           ", "U(ntil Done Net Sessions)      ", "V(iew net list)\n",
  826.     "X(Exit)               ", "Y(toggle NetLog)               ", "Z(toggle NetDebug\n",
  827.     #ifdef ZNEEDED
  828.     "Z",
  829.     #endif
  830.     ""
  831.  
  832.     };
  833.   int AdminPriorityMail(char *line);
  834.   /* If we don't net, don't allow this. */
  835.   if (!cfg.BoolFlags.netParticipant)
  836.     {
  837.     SysopInfoReport(NO_MENU, "Networking is disabled on this installation.\n ");
  838.     return ;
  839.  
  840.     }
  841.   id = RegisterSysopMenu("netopt.mnu", NetMiscOpts,Net_Prompt);
  842.   do
  843.     {
  844.     outFlag = OUTOK;
  845.     RegisterThisMenu("netopt.mnu", NetMiscOpts);
  846.     SysopMenuPrompt(id, "\n Net function: ");
  847.     switch (GetSysopMenuChar(id))
  848.       {
  849.       case ERROR:
  850.       case 'X':
  851.       CloseSysopMenu(id);
  852.       return;
  853.       case 'Y':  /* toggle net log flag */
  854.         logNetResults = ( logNetResults ) ? FALSE : TRUE;
  855.         mPrintf("Network log is turned %s\n ",(logNetResults) ? "on ":"off");
  856.         break;
  857.       case 'Z':  /* toggle net debug flag */
  858.         netDebug = ( netDebug ) ? FALSE : TRUE;
  859.         mPrintf("Network Debug is turned %s\n ",(netDebug) ? "on ":"off");
  860.         mPrintf("Network log is turned %s\n ",(logNetResults) ? "on ":"off");
  861.         break;
  862.       case 'P':
  863.       getList(AdminPriorityMail, "Systems and Priority Mail",
  864.       NAMESIZE, TRUE);
  865.       break;
  866.       case 'I':
  867.       ForceAnytime();
  868.       sPrintf(work, "now %s.\n ", ForceNet ? "ON" : "OFF");
  869.       SysopInfoReport(id, work);
  870.       break;
  871.       case 'R':   /* File requests */
  872.       SysopRequestString(id, "SYSTEM", who, sizeof who, 0);
  873.       if (!ReqNodeName(NULL, who, NULL, FALSE, FALSE, FALSE,
  874.       FALSE, TRUE, &netBuf))
  875.       break;
  876.       fileRequest();
  877.       break;
  878.       case 'S':   /* File transmissions */
  879.       SysopRequestString(id, "SYSTEM", who, sizeof who, 0);
  880.       if (!ReqNodeName(NULL, who, NULL, FALSE, FALSE, FALSE,
  881.       FALSE, TRUE, &netBuf))
  882.       break;
  883.       getSendFiles(id, who);
  884.       break;
  885.       case 'C':   /* Set users' LD credits */
  886.       if ((logNo = GetUser(who, &logTmp, TRUE)) == ERROR ||
  887.       logNo == cfg.MAXLOGTAB) break;
  888.       sPrintf(work, "Currently %d credits.", logTmp.credit);
  889.       SysopInfoReport(id, work);
  890.       logTmp.credit = (int) SysopGetNumber(id, "HWMYCR", 0l, 1000l);
  891.       sPrintf(work, "Set to %d.", logTmp.credit);
  892.       SysopInfoReport(id, work);
  893.       if (loggedIn  &&  strCmpU(logBuf.lbname, who) == SAMESTRING)
  894.       logBuf.credit = logTmp.credit;
  895.       putLog(&logTmp, logNo);
  896.       break;
  897.       case 'D':   /* Primitive dial out ability.  Don't get excited */
  898.       if (!onConsole) break;
  899.       if (gotCarrier())
  900.         {
  901.         /* carrier already?  just jump in */
  902.         CloseSysopMenu(id);
  903.         interact(FALSE);
  904.         id = RegisterSysopMenu("netopt.mnu", NetMiscOpts, Net_Prompt);
  905.         break;
  906.  
  907.         }
  908.       /* Get node to call, if none specified abort */
  909.       SysopRequestString(id, "SYSTEM", who, sizeof who, 0);
  910.       if (!ReqNodeName(NULL, who, NULL, FALSE, TRUE, FALSE, FALSE,
  911.       TRUE, &netBuf))
  912.         {
  913.         break;
  914.  
  915.         }
  916.       /* How many times should we try to call? */
  917.       if ((Redials = SysopGetNumber(id, "REDIAL", 0l,
  918.       65000l)) <= 0l)
  919.       Redials = 1l;       /* allow empty C/R to generate 1. */
  920.       /* Modem should be disabled since we're in CONSOLE mode. */
  921.       id2 = SysopContinual(netBuf.netName, "DIALIT", 50, 13);
  922.       EnableModem(FALSE);
  923.       for (; Redials > 0l; Redials--)
  924.         {
  925.         /* if successful call, start chattin'! */
  926.         if (makeCall(FALSE, id2))
  927.           {
  928.           SysopCloseContinual(id2);
  929.           id2 = NO_MENU;
  930.           CloseSysopMenu(id);
  931.           mputChar(BELL);
  932.           interact(FALSE);
  933.           id = RegisterSysopMenu("netopt.mnu", NetMiscOpts,Net_Prompt);
  934.           break;
  935.  
  936.           }
  937.         /* This handles an abort from kbd */
  938.         if (KBReady())
  939.           {
  940.           getCh();
  941.           /* Hope this turns off modem */
  942.           outMod(' '); pause(2);
  943.           DisableModem(FALSE);
  944.           break;
  945.  
  946.           }
  947.         /* printf("Failed\n"); */
  948.         /* Let modem stabilize for a moment. */
  949.         for (startTimer(WORK_TIMER);chkTimeSince(WORK_TIMER) < 3l; )
  950.         ;
  951.  
  952.         }
  953.       SysopCloseContinual(id2);
  954.       /*
  955.       * If we don't have carrier disable the modem.  We have this
  956.       * check in case sysop wants to perform download within
  957.       * Citadel.
  958.       */
  959.       if (!gotCarrier())
  960.         {
  961.         DisableModem(FALSE);
  962.         modStat = haveCarrier = FALSE;
  963.  
  964.         }
  965.       break;
  966.       case 'V':   /* View the net list. */
  967.       CloseSysopMenu(id);
  968.       doCR();
  969.       writeNet(TRUE, FALSE);
  970.       if (NeedSysopInpPrompt()) modIn();
  971.       id = RegisterSysopMenu("netopt.mnu", NetMiscOpts, Net_Prompt);
  972.       break;
  973.       case 'L':
  974.       CloseSysopMenu(id);
  975.       writeNet(TRUE, TRUE);
  976.       if (NeedSysopInpPrompt()) modIn();
  977.       id = RegisterSysopMenu("netopt.mnu", NetMiscOpts, Net_Prompt);
  978.       break;
  979.       case 'A':   /* Add a new node to the list */
  980.       addNetNode();
  981.       break;
  982.       case 'E':   /* Edit a node that is on the list */
  983.       SysopRequestString(id, "EDITSY", who, sizeof who,0);
  984.       if (!ReqNodeName(NULL, who, NULL, FALSE, TRUE, FALSE, TRUE, TRUE,
  985.       &netBuf))
  986.       break;
  987.       CloseSysopMenu(id);
  988.       editNode();
  989.       id = RegisterSysopMenu("netopt.mnu", NetMiscOpts, Net_Prompt);
  990.       break;
  991.       case 'N':   /* Give someone net privileges. */
  992.       NetPrivs(who);
  993.       break;
  994.       case 'U':
  995.       id2 = SysopContinual(" Net Session ", "", 30, 4);
  996.       SysopContinualString(id2, "MEMBER", work, 3, 0);
  997.       tmp.first = atoi(work);
  998.       if (tmp.first < 1 || tmp.first > MAX_NET - 1)
  999.         {
  1000.         if (strLen(work) != 0)
  1001.         SysopError(id2, "Illegal Member Net");
  1002.  
  1003.         }
  1004.       else
  1005.         {
  1006.         if (SearchList(&UntilNetSessions, &tmp) != NULL)
  1007.           {
  1008.           SysopInfoReport(NO_MENU, "Net session deactivated.\n");
  1009.           KillData(&UntilNetSessions, &tmp);
  1010.  
  1011.           }
  1012.         else
  1013.           {
  1014.           SysopContinualString(id2, "DURATI", work, 4, 0);
  1015.           duration = atol(work);
  1016.           if (duration < 1l)
  1017.           SysopError(id2, "Illegal Duration");
  1018.           else
  1019.           AddData(&UntilNetSessions,MakeTwo(tmp.first,duration),
  1020.           NULL, FALSE);
  1021.  
  1022.           }
  1023.  
  1024.         }
  1025.       SysopCloseContinual(id2);
  1026.       break;
  1027.       #ifdef ZNEEDED
  1028.       case 'Z':
  1029.       inNet = NORMAL_NET;
  1030.       AddNetMsgs("tempmail.$$$", inMail, FALSE, MAILROOM, TRUE);
  1031.       inNet = NON_NET;
  1032.       break;
  1033.       #endif
  1034.  
  1035.       }
  1036.  
  1037.     }
  1038.   while (onLine());
  1039.  
  1040.   }
  1041. /*
  1042. * AdminPriorityMail()
  1043. *
  1044. * This handles the administration of priority mail.
  1045. */
  1046. int AdminPriorityMail(char *system)
  1047.   {
  1048.   if (searchNameNet(system, &netBuf) == ERROR)
  1049.     {
  1050.     SysopError(NO_MENU, "No such system\n");
  1051.  
  1052.     }
  1053.   else
  1054.     {
  1055.     if (!(netBuf.nbflags.normal_mail ||
  1056.     netBuf.nbflags.HasRouted ||
  1057.     DomainFlags[thisNet]))
  1058.       {
  1059.       SysopError(NO_MENU, "No outgoing mail.\n");
  1060.       return TRUE;
  1061.  
  1062.       }
  1063.     else if ((netBuf.MemberNets & PRIORITY_MAIL))
  1064.       {
  1065.       SysopInfoReport(NO_MENU, "Priority mail deactivated.\n");
  1066.       PriorityMail--;
  1067.       netBuf.MemberNets &= ~(PRIORITY_MAIL);
  1068.  
  1069.       }
  1070.     else
  1071.       {
  1072.       PriorityMail++;
  1073.       netBuf.MemberNets |= (PRIORITY_MAIL);
  1074.  
  1075.       }
  1076.     putNet(thisNet, &netBuf);
  1077.  
  1078.     }
  1079.   return TRUE;
  1080.  
  1081.   }
  1082. /*
  1083. * NetPrivs()
  1084. *
  1085. * This will setup net privs for someone.
  1086. */
  1087. void NetPrivs(label who)
  1088.   {
  1089.   int logNo, result;
  1090.   if ((logNo = GetUser(who, &logTmp, TRUE)) == ERROR) return;
  1091.   if (logNo == cfg.MAXLOGTAB)
  1092.     {
  1093.     result = DoAllQuestion("GVNTPR","TANTPR");
  1094.     if (result == ERROR) return;
  1095.     for (logNo = 0; logNo < cfg.MAXLOGTAB; logNo++)
  1096.       {
  1097.       getLog(&logTmp, logNo);
  1098.       if (!onConsole) mPrintf(".");
  1099.       if (logTmp.lbflags.L_INUSE && logTmp.lbflags.NET_PRIVS != result)
  1100.         {
  1101.         logTmp.lbflags.NET_PRIVS = result;
  1102.         putLog(&logTmp, logNo);
  1103.  
  1104.         }
  1105.  
  1106.       }
  1107.     return;
  1108.  
  1109.     }
  1110.   Output_Citadel_Message((logTmp.lbflags.NET_PRIVS) ? "USRNNT" : "USRNET",
  1111.   (long)who, NULL, NULL);
  1112.   if (!SysopGetYesNo(NO_MENU, NULL, "CONFRM"))   return;
  1113.   logTmp.lbflags.NET_PRIVS = !logTmp.lbflags.NET_PRIVS;
  1114.   if (strCmpU(logTmp.lbname, logBuf.lbname) == SAMESTRING)
  1115.   logBuf.lbflags.NET_PRIVS = logTmp.lbflags.NET_PRIVS;
  1116.   putLog(&logTmp, logNo);
  1117.  
  1118.   }
  1119. static char AddedFiles;
  1120. /*
  1121. * getSendFiles()
  1122. *
  1123. * This will get the files from the sysop to send to another system.
  1124. */
  1125. void getSendFiles(MenuId id, label sysName)
  1126.   {
  1127.   SYS_FILE       sysFile;
  1128.   char     temp[10];
  1129.   extern char    *APPEND_ANY;
  1130.   sPrintf(temp, "%d.sfl", thisNet);
  1131.   makeSysName(sysFile, temp, &cfg.netArea);
  1132.   if ((upfd = safeopen(sysFile, APPEND_ANY)) == NULL)
  1133.     {
  1134.     SysopPrintf(id, "Couldn't open %s for update?\n ", sysFile);
  1135.     return ;
  1136.  
  1137.     }
  1138.   sPrintf(msgBuf.mbtext, "Files to send to %s", sysName);
  1139.   AddedFiles = FALSE;
  1140.   getList(addSendFile, msgBuf.mbtext, 126, TRUE);
  1141.   fclose(upfd);
  1142.   if (AddedFiles)
  1143.     {
  1144.     netBuf.nbflags.send_files = TRUE;
  1145.     putNet(thisNet, &netBuf);
  1146.  
  1147.     }
  1148.  
  1149.   }
  1150. /*
  1151. * addSendFile()
  1152. *
  1153. * This is a work function, called indirectly by getList().
  1154. */
  1155. int addSendFile(char *Files)
  1156.   {
  1157.   struct fl_send sendWhat;
  1158.   extern MenuId GetListId;
  1159.   if (sysGetSendFilesV2(GetListId, Files, &sendWhat))
  1160.     {
  1161.     putSLNet(sendWhat, upfd);
  1162.     AddedFiles = TRUE;
  1163.  
  1164.     }
  1165.   return TRUE;
  1166.  
  1167.   }
  1168. /*
  1169. * addNetNode()
  1170. *
  1171. * This adds a node to the net listing.
  1172. */
  1173. void addNetNode()
  1174.   {
  1175.   int searcher, gen;
  1176.   char  goodAnswer, found;
  1177.   extern char *ALL_LOCALS;
  1178.   MenuId id;
  1179.   id = SysopContinual("", "", 2 * NAMESIZE, 5);
  1180.   for (searcher = 0; searcher < cfg.netSize; searcher++)
  1181.   if (netTab[searcher].ntflags.in_use == FALSE) break;
  1182.   if (searcher != cfg.netSize)
  1183.     {
  1184.     getNet(searcher, &netBuf);
  1185.     found = TRUE;
  1186.     gen = (netBuf.nbGen + 1) % NET_GEN;
  1187.  
  1188.     }
  1189.   else
  1190.     {
  1191.     found = FALSE;
  1192.     gen = 0;
  1193.  
  1194.     }
  1195.   killNetBuf(&netBuf);
  1196.   zero_struct(netBuf);  /* Useful initialization       */
  1197.   initNetBuf(&netBuf);
  1198.   /* Get a unique name */
  1199.   do
  1200.     {
  1201.     SysopContinualString(id, "SYSTEM", netBuf.netName, NAMESIZE, 0);
  1202.     if (strLen(netBuf.netName) == 0)
  1203.       {
  1204.       SysopCloseContinual(id);
  1205.       return;
  1206.  
  1207.       }
  1208.     if ((goodAnswer = strCmpU(ALL_LOCALS, netBuf.netName)) == 0)
  1209.     SysopError(id, "Sorry, reserved name\n ");
  1210.     else if ((goodAnswer = searchNameNet(netBuf.netName, &netTemp)==ERROR) == 0)
  1211.       {
  1212.       sPrintf(msgBuf.mbtext, "Sorry, %s is already in use.\n ",
  1213.       netBuf.netName);
  1214.       SysopError(id, msgBuf.mbtext);
  1215.  
  1216.       }
  1217.     else if (strchr(netBuf.netName, '_') != NULL)
  1218.       {
  1219.       goodAnswer = FALSE;
  1220.       SysopError(id, "Please don't use '_' in the system name.\n ");
  1221.  
  1222.       }
  1223.  
  1224.     }
  1225.   while (!goodAnswer);
  1226.   /* Get a unique ID */
  1227.   do
  1228.     {
  1229.     goodAnswer = TRUE;
  1230.     SysopContinualString(id, "SYSTID", netBuf.netId, NAMESIZE, 0);
  1231.     if (strLen(netBuf.netId) == 0)
  1232.       {
  1233.       SysopCloseContinual(id);
  1234.       return;
  1235.  
  1236.       }
  1237.     if (searchNet(netBuf.netId, &netTemp) != ERROR)
  1238.       {
  1239.       sPrintf(msgBuf.mbtext, "Sorry, %s is already in use.\n ",
  1240.       netBuf.netId);
  1241.       SysopError(id, msgBuf.mbtext);
  1242.       goodAnswer = FALSE;
  1243.  
  1244.       }
  1245.  
  1246.     }
  1247.   while (!goodAnswer);
  1248.   netBuf.baudCode = (int) SysopGetNumber(id, "BAUDST", 0l, 8l);
  1249.   netBuf.nbflags.local  = SysopGetYesNo(id, NULL, "ISSYSL");
  1250.   netBuf.nbflags.in_use = TRUE;
  1251.   netBuf.MemberNets   = 1;     /* Default */
  1252.   netBuf.nbGen    = gen;   /* Update generation #  */
  1253.   netBuf.nbRoute    = -1;
  1254.   netBuf.nbflags.RouteTo  = TRUE;
  1255.   netBuf.nbflags.RouteFor = TRUE;
  1256.   if (!found)
  1257.     {
  1258.     if (cfg.netSize != 0)
  1259.     netTab = (NetTable *)
  1260.     realloc(netTab, sizeof (*netTab) * ++cfg.netSize);
  1261.     else
  1262.     netTab = (NetTable *)
  1263.     GetDynamic(sizeof(*netTab) * ++cfg.netSize);
  1264.     searcher = cfg.netSize - 1;
  1265.     netTab[searcher].netTRooms = (SharedRoom *) GetDynamic(SR_BULK);
  1266.  
  1267.     }
  1268.   if (cfg.BoolFlags.debug) splitF(netLog, "Calling putNet @aNN, slot %d\n", searcher);
  1269.   putNet(searcher, &netBuf);
  1270.   InitVNode(searcher);
  1271.   DomainInit(FALSE);    /* so we can redirect easily enough */
  1272.   SysopCloseContinual(id);
  1273.  
  1274.   }
  1275. /*
  1276. * addNetMem()
  1277. *
  1278. * This adds nets to this system's list.
  1279. */
  1280. int addNetMem(char *netnum)
  1281.   {
  1282.   int num;
  1283.   MULTI_NET_DATA temp;
  1284.   num = atoi(netnum);
  1285.   if (num < 1 || num > MAX_NET - 1)
  1286.     {
  1287.     SysopError(NO_MENU, "There are only 31 nets to choose from.\n");
  1288.     return TRUE;
  1289.  
  1290.     }
  1291.   temp = 1l;
  1292.   temp <<= (num-1);
  1293.   netBuf.MemberNets |= temp;
  1294.   return TRUE;
  1295.  
  1296.   }
  1297. /*
  1298. * subNetMem()
  1299. *
  1300. * This takes nets from a system's list.
  1301. */
  1302. int subNetMem(char *netnum)
  1303.   {
  1304.   int num;
  1305.   MULTI_NET_DATA temp;
  1306.   num = atoi(netnum);
  1307.   if (num < 1 || num > MAX_NET - 1)
  1308.     {
  1309.     SysopError(NO_MENU, "There are only 31 nets to choose from.");
  1310.     return TRUE;
  1311.  
  1312.     }
  1313.   temp = 1l;
  1314.   temp <<= (num-1);
  1315.   temp = ~temp;
  1316.   netBuf.MemberNets &= temp;
  1317.   return TRUE;
  1318.  
  1319.   }
  1320. /*
  1321. * editNode()
  1322. *
  1323. * This function will edit a net node.
  1324. */
  1325. void editNode()
  1326.   {
  1327.   label  temp2;
  1328.   char   title[50], work[50], temp[NAMESIZE*3];
  1329.   int    place, compress;
  1330.   MenuId id;
  1331.   char   exttemp;
  1332.   char   *NetEditOpts[] =
  1333.     {
  1334.     "A(ccess setting)  ", "B(aud code change)    ", "C(ondensed name)\n",
  1335.     "D(ownload toggle) ", "E(xternal Dialer)     ", "F(ast Transfers)\n",
  1336.     "I(D change)       ", "K(ill node from list) ", "L(ocal setting)\n",
  1337.     "M(ember Nets)     ", "N(ame change)         ", "O(thernet toggle)\n",
  1338.     "P(asswords)       ", "R(ooms shared)        ", "S(pine settings)\n",
  1339.     "V(alues)          ", "X(Exit)\n",
  1340.     #ifdef NEEDED
  1341.     "ZKludge",
  1342.     #endif
  1343.     ""
  1344.  
  1345.     };
  1346.   place = thisNet;    /* this is really a kludge, but for now will serve */
  1347.   if (!NeedSysopInpPrompt())  /* rather icky, really.  fix someday? */
  1348.   NodeValues(NO_MENU);
  1349.   sPrintf(title, "\nEditing %s\n", netBuf.netName);
  1350.   id = RegisterSysopMenu("netedit.mnu", NetEditOpts, title);
  1351.   while (onLine())
  1352.     {
  1353.     outFlag = OUTOK;
  1354.     sPrintf(work, "\n (%s) edit fn: ", netBuf.netName);
  1355.     SysopMenuPrompt(id, work);
  1356.     switch (GetSysopMenuChar(id))
  1357.       {
  1358.       case ERROR:
  1359.       case 'X':
  1360.       putNet(place, &netBuf);
  1361.       CloseSysopMenu(id);
  1362.       return;
  1363.       case 'E':
  1364.       exttemp = netBuf.nbflags.ExternalDialer;
  1365.       if ((netBuf.nbflags.ExternalDialer =
  1366.       SysopGetYesNo(id, NULL, "USEDIL")))
  1367.         {
  1368.         SysopRequestString(id, "DIALER",netBuf.access,sizeof netBuf.access,0);
  1369.         }
  1370.       else if (exttemp) /* clear old information */
  1371.       netBuf.access[0] = 0;
  1372.       break;
  1373.       case 'A':
  1374.       SysopRequestString(id, "ACCESS", netBuf.access,
  1375.       sizeof netBuf.access, 0);
  1376.       break;
  1377.       case 'B':
  1378.       netBuf.baudCode = (int) SysopGetNumber(id, "BAUDST", 0l, 8l);
  1379.       break;
  1380.       case 'C':
  1381.       temp[0] = temp[1] = temp[2] = '\0';
  1382.       SysopRequestString(id, "CONSNM", temp, 3, 0);
  1383.       if (searchNameNet(temp, &netTemp) != ERROR)
  1384.         {
  1385.         sPrintf(work, "'%s' is already in use.", temp);
  1386.         SysopError(id, work);
  1387.  
  1388.         }
  1389.       else
  1390.       strCpy(netBuf.nbShort, temp);
  1391.       break;
  1392.       case 'D':
  1393.       sPrintf(work, "for %s %s.\n ",
  1394.       netBuf.netName, netBuf.nbflags.NoDL ? "ON" : "OFF");
  1395.       SysopInfoReport(id, work);
  1396.       netBuf.nbflags.NoDL = !netBuf.nbflags.NoDL;
  1397.       break;
  1398.       case 'F':
  1399.       netBuf.nbflags.MassTransfer = !netBuf.nbflags.MassTransfer;
  1400.       if (netBuf.nbflags.MassTransfer)
  1401.         {
  1402.         /* kludges - next major release make into char */
  1403.         netBuf.nbflags.Zoo = FALSE;
  1404.         netBuf.nbflags.Lzh = FALSE;
  1405.         netBuf.nbflags.Lha = FALSE;
  1406.         netBuf.nbflags.Arc = FALSE;
  1407.         if ((compress = GetUserCompression()) == NO_COMP)
  1408.           {
  1409.           netBuf.nbflags.MassTransfer = FALSE;
  1410.           RegisterThisMenu("netedit.mnu", NetEditOpts);
  1411.           break;
  1412.  
  1413.           }
  1414.         switch (compress)
  1415.           {
  1416.           case LZH_COMP: netBuf.nbflags.Lzh = TRUE;break;
  1417.           case ZOO_COMP: netBuf.nbflags.Zoo = TRUE;break;
  1418.           case ARC_COMP: netBuf.nbflags.Arc = TRUE;break;
  1419.           case LHA_COMP: netBuf.nbflags.Lha = TRUE;break;
  1420.  
  1421.           }
  1422.         RegisterThisMenu("netedit.mnu", NetEditOpts);
  1423.  
  1424.         }
  1425.       sPrintf(work, "for %s %s.\n ", netBuf.netName,
  1426.       netBuf.nbflags.MassTransfer ? "ON" : "OFF");
  1427.       SysopInfoReport(id, work);
  1428.       if (netBuf.nbflags.MassTransfer)
  1429.         {
  1430.         MakeNetCacheName(temp, thisNet);
  1431.         mkdir(temp);
  1432.  
  1433.         }
  1434.       putNet(thisNet, &netBuf);
  1435.       /* more work here? */
  1436.       break;
  1437.       case 'R':
  1438.       CloseSysopMenu(id);
  1439.       EachSharedRoom(thisNet, DumpRoom, DumpVRoom, NULL);
  1440.       if (onConsole) modIn();
  1441.       sPrintf(title, " Editing %s ", netBuf.netName);
  1442.       id = RegisterSysopMenu("netedit.mnu", NetEditOpts, title);
  1443.       break;
  1444.       case 'N':
  1445.       SysopRequestString(id, "SYSTEM", temp, NAMESIZE, 0);
  1446.       if (strLen(temp) != 0) strCpy(netBuf.netName, temp);
  1447.       if (SysopGetYesNo(id, NULL, "NEWSYS"))
  1448.         {
  1449.         netBuf.nbGen = (netBuf.nbGen + 1) % NET_GEN;
  1450.         KillTempFiles(thisNet);
  1451.         ClearRoomSharing();
  1452.  
  1453.         }
  1454.       break;
  1455.       case 'I':
  1456.       SysopRequestString(id, "SYSTID", temp, NAMESIZE, 0);
  1457.       if (strLen(temp) != 0) strCpy(netBuf.netId, temp);
  1458.       if (SysopGetYesNo(id, NULL, "NEWSYS"))
  1459.         {
  1460.         netBuf.nbGen = (netBuf.nbGen + 1) % NET_GEN;
  1461.         KillTempFiles(thisNet);
  1462.         ClearRoomSharing();
  1463.  
  1464.         }
  1465.       break;
  1466.       case 'K':
  1467.       if (netBuf.nbflags.normal_mail)
  1468.         {
  1469.         sPrintf(work, "There is outgoing mail outstanding.\n ");
  1470.         SysopInfoReport(id, work);
  1471.  
  1472.         }
  1473.       if (netBuf.nbflags.room_files)
  1474.         {
  1475.         sPrintf(work, "There are file requests outstanding.\n ");
  1476.         SysopInfoReport(id, work);
  1477.  
  1478.         }
  1479.       if (SysopGetYesNo(id, NULL, "CONFRM"))
  1480.         {
  1481.         netBuf.nbflags.in_use = FALSE;
  1482.         putNet(place, &netBuf);
  1483.         KillTempFiles(thisNet);
  1484.         KillCacheFiles(thisNet);
  1485.         CloseSysopMenu(id);
  1486.         return;
  1487.  
  1488.         }
  1489.       break;
  1490.       case 'L':
  1491.       netBuf.nbflags.local = SysopGetYesNo(id, NULL, "ISSYSL");
  1492.       break;
  1493.       case 'P':
  1494.       CloseSysopMenu(id);
  1495.       Output_Citadel_Message("NTPSWO",
  1496.                              (long)netBuf.OurPwd,
  1497.                              (long)netBuf.TheirPwd, NULL);
  1498.       if (getXString("NTNPWO", temp2, NAMESIZE, "", ""))
  1499.       strCpy(netBuf.OurPwd, temp2);
  1500.       if (getXString("NTNPWT", temp2, NAMESIZE, "", ""))
  1501.       strCpy(netBuf.TheirPwd, temp2);
  1502.       id = RegisterSysopMenu("netedit.mnu", NetEditOpts, title);
  1503.       break;
  1504.       case 'M':
  1505.       getList(addNetMem, "Nets to add to this system's member list",
  1506.       5, TRUE);
  1507.       getList(subNetMem,"Nets to take off this system's member list",
  1508.       5, TRUE);
  1509.       break;
  1510.       case 'S':
  1511.       Output_Citadel_Message("ISPINE",(long)netBuf.netName,NULL,NULL);
  1512.       if (!(netBuf.nbflags.spine = SysopGetYesNo(id, NULL, "CONFRM")))
  1513.         {
  1514.         Output_Citadel_Message("SPINEU",(long)netBuf.netName,NULL,NULL);
  1515.         netBuf.nbflags.is_spine =
  1516.         SysopGetYesNo(id, NULL, "CONFRM");
  1517.  
  1518.         }
  1519.       else
  1520.       netBuf.nbflags.is_spine = FALSE;
  1521.       break;
  1522.       case 'O':
  1523.       Output_Citadel_Message((netBuf.nbflags.OtherNet) ? "NOTHER" : "OTHERN",NULL, NULL, NULL);
  1524.       netBuf.nbflags.OtherNet = !netBuf.nbflags.OtherNet;
  1525.       break;
  1526.       case 'V':
  1527.       NodeValues(id);
  1528.       break;
  1529.       #ifdef NEEDED
  1530.       case 'Z':
  1531.       netBuf.nbHiRouteInd = (int) getNumber("KLUDGE", 0l, 255l);
  1532.       netBuf.nbflags.HasRouted = TRUE;
  1533.       break;
  1534.       #endif
  1535.  
  1536.       }
  1537.  
  1538.     }
  1539.  
  1540.   }
  1541. /*
  1542. * KillTempFiles()
  1543. *
  1544. * This eliminates unneeded temp files for dead node.
  1545. */
  1546. void KillTempFiles(int which)
  1547.   {
  1548.   label    temp;
  1549.   SYS_FILE temp2;
  1550.   sPrintf(temp, "%d.ml", which);
  1551.   makeSysName(temp2, temp, &cfg.netArea);
  1552.   unlink(temp2);
  1553.   netBuf.nbflags.normal_mail = FALSE;
  1554.   sPrintf(temp, "%d.rfl", which);
  1555.   makeSysName(temp2, temp, &cfg.netArea);
  1556.   unlink(temp2);
  1557.   netBuf.nbflags.room_files = FALSE;
  1558.   sPrintf(temp, "%d.sfl", which);
  1559.   makeSysName(temp2, temp, &cfg.netArea);
  1560.   unlink(temp2);
  1561.   netBuf.nbflags.send_files = FALSE;
  1562.   sPrintf(temp, "%d.vtx", which);
  1563.   makeSysName(temp2, temp, &cfg.netArea);
  1564.   unlink(temp2);
  1565.   InitVNode(thisNet);
  1566.  
  1567.   }
  1568. /*
  1569. * ClearRoomSharing()
  1570. *
  1571. * This clears room sharing out completely for this node.
  1572. */
  1573. void ClearRoomSharing()
  1574.   {
  1575.   int i;
  1576.   for (i = 0; i < SHARED_ROOMS; i++)
  1577.   netBuf.netRooms[i].srgen = 0;
  1578.  
  1579.   }
  1580. /*
  1581. * NodeValues()
  1582. *
  1583. * This function prints out the values for the current node.
  1584. */
  1585. void NodeValues(MenuId id)
  1586.   {
  1587.   int i, first;
  1588.   MULTI_NET_DATA h;
  1589.   sPrintf(msgBuf.mbtext, "\n Node #%d: %s", thisNet, netBuf.netName);
  1590.   if (strLen(netBuf.nbShort))
  1591.   sPrintf(lbyte(msgBuf.mbtext), " (%s)", netBuf.nbShort);
  1592.   sPrintf(lbyte(msgBuf.mbtext), "\n Id: %s (%slocal @ %s)\n ",
  1593.   netBuf.netId,
  1594.   netBuf.nbflags.local ? "" : "non",
  1595.   SupportedBauds[netBuf.baudCode]);
  1596.   if (netBuf.nbflags.ExternalDialer)
  1597.   sPrintf(lbyte(msgBuf.mbtext), "External Dialer Information: %s\n ", netBuf.access);
  1598.   if (strLen(netBuf.access) != 0 && !netBuf.nbflags.ExternalDialer)
  1599.   sPrintf(lbyte(msgBuf.mbtext), "Access: %s\n ", netBuf.access);
  1600.   if (netBuf.nbflags.spine)
  1601.   sPrintf(lbyte(msgBuf.mbtext), "We are a spine for this system\n ");
  1602.   else if (netBuf.nbflags.is_spine)
  1603.   sPrintf(lbyte(msgBuf.mbtext), "This system is a spine\n ");
  1604.   if (netBuf.nbflags.OtherNet)
  1605.   sPrintf(lbyte(msgBuf.mbtext), "This system is designated as OtherNet.\n ");
  1606.   if (netBuf.nbflags.normal_mail)
  1607.   sPrintf(lbyte(msgBuf.mbtext), "There is outgoing Mail>.\n ");
  1608.   if (netBuf.nbflags.HasRouted)
  1609.   sPrintf(lbyte(msgBuf.mbtext), "There is outgoing RouteMail.\n ");
  1610.   if (DomainFlags[thisNet])
  1611.   sPrintf(lbyte(msgBuf.mbtext), "There is outgoing DomainMail.\n ");
  1612.   if (netBuf.nbflags.room_files)
  1613.   sPrintf(lbyte(msgBuf.mbtext), "There are file requests outstanding.\n ");
  1614.   if (netBuf.nbflags.send_files)
  1615.   sPrintf(lbyte(msgBuf.mbtext), "There are files to be sent.\n ");
  1616.   if (netBuf.nbflags.MassTransfer)
  1617.   sPrintf(lbyte(msgBuf.mbtext), "Fast Transfers on (using %s).\n ",
  1618.   GetCompEnglish(GetCompression(thisNet)));
  1619.   if (netBuf.MemberNets != 0l)
  1620.     {
  1621.     sPrintf(lbyte(msgBuf.mbtext), "This system is assigned to the following nets: ");
  1622.     for (i = 0, first = 1, h = 1l; i < MAX_NET; i++)
  1623.       {
  1624.       if (h & netBuf.MemberNets)
  1625.         {
  1626.         if (!first)
  1627.         sPrintf(lbyte(msgBuf.mbtext), ", ");
  1628.         else first = FALSE;
  1629.         sPrintf(lbyte(msgBuf.mbtext), "%d", i+1); /* Yes - +1. Number the bits starting with 1 */
  1630.  
  1631.         }
  1632.       h <<= 1;
  1633.  
  1634.       }
  1635.     sPrintf(lbyte(msgBuf.mbtext), ".\n ");
  1636.  
  1637.     }
  1638.   else sPrintf(lbyte(msgBuf.mbtext), "This system is currently disabled.\n ");
  1639.   sPrintf(lbyte(msgBuf.mbtext), "Last connected: %s\n", AbsToReadable(netBuf.nbLastConnect));
  1640.   SysopDisplayInfo(id, msgBuf.mbtext, " Values ");
  1641.  
  1642.   }
  1643. /*
  1644. * fileRequest()
  1645. *
  1646. * This handles the administration of requesting files from another system.
  1647. */
  1648. void fileRequest()
  1649.   {
  1650.   struct fl_req file_data;
  1651.   label    data;
  1652.   char     loc[100], *c, *work;
  1653.   SYS_FILE fn;
  1654.   char     abort;
  1655.   FILE     *temp;
  1656.   int      place;
  1657.   extern char *APPEND_ANY;
  1658.   char     ambiguous, again;
  1659.   MenuId   id;
  1660.   place = thisNet;    /* again, a kludge to be killed later */
  1661.   id = SysopContinual("", "", 75, 10);
  1662.   SysopContinualString(id, "ROMNAM", file_data.room, NAMESIZE, 0);
  1663.   if (strLen(file_data.room) == 0)
  1664.     {
  1665.     SysopCloseContinual(id);
  1666.     return;
  1667.  
  1668.     }
  1669.   SysopContinualString(id, "EFILEN", loc, sizeof loc, 0);
  1670.   if (strLen(loc) == 0)
  1671.     {
  1672.     SysopCloseContinual(id);
  1673.     return;
  1674.  
  1675.     }
  1676.   ambiguous = !(strchr(loc, '*') == NULL && strchr(loc, '?') == NULL &&
  1677.   strchr(loc, ' ') == NULL);
  1678.   abort = !netGetAreaV2(id, loc, &file_data, ambiguous);
  1679.   if (!abort)
  1680.     {
  1681.     sPrintf(data, "%d.rfl", place);
  1682.     makeSysName(fn, data, &cfg.netArea);
  1683.     if ((temp = safeopen(fn, APPEND_ANY)) == NULL)
  1684.       {
  1685.       SysopPrintf(id, "Couldn't append to '%s'????", fn);
  1686.  
  1687.       }
  1688.     else
  1689.       {
  1690.       work = loc;
  1691.       do
  1692.         {
  1693.         again = (c = strchr(work, ' ')) != NULL;
  1694.         if (again) *c = 0;
  1695.         strCpy(file_data.roomfile, work);
  1696.         if (ambiguous) strCpy(file_data.filename, work);
  1697.         fwrite(&file_data, sizeof (file_data), 1, temp);
  1698.         if (again) work = c + 1;
  1699.  
  1700.         }
  1701.       while (again);
  1702.       netBuf.nbflags.room_files = TRUE;
  1703.       putNet(place, &netBuf);
  1704.       fclose(temp);
  1705.  
  1706.       }
  1707.  
  1708.     }
  1709.   SysopCloseContinual(id);
  1710.  
  1711.   }
  1712. /*
  1713. * roomsShared()
  1714. *
  1715. * This function returns TRUE if this system has a room with new data to share
  1716. * (orSomething).
  1717. */
  1718. char roomsShared(int slot)
  1719.   {
  1720.   int ROutGoing(SharedRoom *room, int system, int index, int roomslot,void *d);
  1721.   char OutGoing;
  1722.   /* We only want to make one "successful" call per voluntary net session */
  1723.   if ((inNet == UNTIL_NET || inNet == NORMAL_NET || inNet == ANYTIME_NET ) &&
  1724.   pollCall[slot] <= 0)
  1725.   return FALSE;
  1726.   /*
  1727.   * Rules:
  1728.   * We check each slot of the shared rooms list for this node.  For
  1729.   * each one that is in use, we do the following:
  1730.   *   HOSTS ARE OBSOLETE!
  1731.   * a) if we are regional host for the room and other system is
  1732.   *    a backbone, then don't assume we need to call.
  1733.   * b) if we are backboning the room, check to see what status of this
  1734.   *    room for other system is.
  1735.   *    1) If we are Passive Backbone, then we need not call.
  1736.   *    2) If we are Active Backbone, then do call.
  1737.   *    3) The Regional Host looks screwy.  This may be a bug.
  1738.   * c) If none of the above applies, implies we are a simple Peon, so
  1739.   *    we simply check to see if we have outgoing messages, and if so,
  1740.   *    return TRUE indicating that we need to call; otherwise, continue
  1741.   *    search.
  1742.   *
  1743.   * LATER NOTE: now this is split up due to the use of EachSharedRoom.
  1744.   */
  1745.   OutGoing = FALSE;
  1746.   EachSharedRoom(slot, ROutGoing, VRNeedCall, &OutGoing);
  1747.   return OutGoing;
  1748.  
  1749.   }
  1750. /*
  1751. * ROutGoing()
  1752. *
  1753. * This decides if the system in question needs to be called due to the
  1754. * situation of the rooms.
  1755. */
  1756. int ROutGoing(SharedRoom *room, int system, int index, int roomslot, void *d)
  1757.   {
  1758.   char *arg;
  1759.   arg = d;
  1760.   if (cfg.BoolFlags.debug)
  1761.     {
  1762.     splitF(netLog,"ROutGoing(**,%d, %d, %d, %08.8lX)\n",system, index, roomslot, d);
  1763.     splitF(netLog,"room->mode = %04.4X\n",room->mode);
  1764.     splitF(netLog,"room->lastMess = %ld\n",room->lastMess);
  1765.     }
  1766.   if (roomTab[roomslot].rtShareType != PEON)
  1767.     {
  1768.     if (GetMode(room->mode) == PASS_BACKBONE)
  1769.     return TRUE;
  1770.     else if (GetMode(room->mode) == REG_HOST ||
  1771.     GetMode(room->mode) == ACTIVE_BACKBONE)
  1772.       {
  1773.       if (inNet == NORMAL_NET)
  1774.         {
  1775.         *arg = TRUE;
  1776.         return ERROR;
  1777.  
  1778.         }
  1779.  
  1780.       }
  1781.  
  1782.     }
  1783.   if (cfg.BoolFlags.debug)
  1784.     {
  1785.     splitF(netLog,"roomTab[%d] = %ld\n",roomslot,roomTab[roomslot].rtlastNet);
  1786.     };
  1787.   if (roomTab[roomslot].rtlastNet > room->lastMess)
  1788.     {
  1789.     *arg = TRUE;
  1790.     return ERROR;
  1791.  
  1792.     }
  1793.   if (cfg.BoolFlags.debug)
  1794.     {
  1795.     splitF(netLog,"GetFA(room->mode) = %d\n",GetFA(room->mode));
  1796.     };
  1797.   if (GetFA(room->mode))
  1798.     {
  1799.     *arg = TRUE;
  1800.     return ERROR;
  1801.  
  1802.     }
  1803.   return TRUE;
  1804.  
  1805.   }
  1806. /*
  1807. * DumpRoom()
  1808. *
  1809. * This dumps out information concerning a shared room, such as the status
  1810. * and the message stuff.
  1811. */
  1812. int DumpRoom(SharedRoom *room, int system, int index, int roomslot, void *d)
  1813.   {
  1814.   char cmd, *s1, *s2, *s3, *name, doit;
  1815.   mPrintf("%-22sRelationship: ", roomTab[roomslot].rtname);
  1816.   Addressing(system, index, &cmd, &s1, &s2, &s3, &name, &doit);
  1817.   mPrintf(name);
  1818.   mPrintf(" (last sent=%ld, netlast=%ld)",
  1819.   room->lastMess, roomTab[roomslot].rtlastNet);
  1820.   if (GetFA(netTab[system].netTRooms[index].mode))
  1821.   mPrintf("*");
  1822.   mPrintf("\n ");
  1823.   return TRUE;
  1824.  
  1825.   }
  1826. /*
  1827. * netResult()
  1828. *
  1829. * This will put a message to the net msg holder, building a message for the
  1830. * Aide room.
  1831. */
  1832. void netResult(char *msg)
  1833.   {
  1834.   if (netMsg != NULL)
  1835.     {
  1836.     fprintf(netMsg, "(%s) %s\n\n", Current_Time(), msg);
  1837.     fflush(netMsg);
  1838.     UsedNetMsg = TRUE;
  1839.  
  1840.     }
  1841.  
  1842.   }
  1843. /*
  1844. * netInfo()
  1845. *
  1846. * This function acquires necessary info from the user when entering a message.
  1847. */
  1848. char netInfo(char GetName)
  1849.   {
  1850.   int    cost;
  1851.   extern char *ALL_LOCALS;
  1852.   extern char *R_SH_MARK;
  1853.   label  domain = "";
  1854.   char   sys[NAMESIZE * 2];
  1855.   char   isdomain, *address;
  1856.   char   work[45];
  1857.   if (thisRoom == MAILROOM)
  1858.     {
  1859.     strCpy(sys, msgBuf.mbaddr);
  1860.     if (!ReqNodeName("SYSTSD", sys, domain, (char) aide,
  1861.     FALSE, GetName, FALSE, FALSE, &netBuf))
  1862.     return FALSE;
  1863.     isdomain = (domain[0] != 0);
  1864.     if (strCmpU(sys, ALL_LOCALS) != SAMESTRING)
  1865.       {
  1866.       if (strCmpU(domain, cfg.nodeDomain + cfg.codeBuf) == SAMESTRING &&
  1867.       (strCmpU(sys, cfg.nodeName + cfg.codeBuf) == SAMESTRING ||
  1868.       strCmpU(sys, UseNetAlias(cfg.nodeName+cfg.codeBuf, TRUE))
  1869.       == SAMESTRING))
  1870.         {
  1871.         mPrintf("Hey, that's this system!\n ");
  1872.         return FALSE;
  1873.  
  1874.         }
  1875.       cost = (isdomain) ? FindCost(domain) : !netBuf.nbflags.local;
  1876.       if (logBuf.credit < cost)
  1877.         {
  1878.         if (HalfSysop())
  1879.           {
  1880.           logBuf.credit += cost;
  1881.  
  1882.           }
  1883.         else
  1884.           {
  1885.           Output_Citadel_Message("NOCRDT", NULL, NULL, NULL);
  1886.           return FALSE;
  1887.  
  1888.           }
  1889.  
  1890.         }
  1891.       if (isdomain)
  1892.         {
  1893.         sPrintf(work, "%s _ %s", sys, domain);
  1894.         address = work;
  1895.  
  1896.         }
  1897.       else address = sys;
  1898.       if (!isdomain && netBuf.nbflags.OtherNet)
  1899.         {
  1900.         mPrintf("%s address", netBuf.netName);
  1901.         getNormStr("", msgBuf.mbOther, O_NET_PATH_SIZE, 0);
  1902.         if (strLen(msgBuf.mbOther) == 0) return FALSE;
  1903.  
  1904.         }
  1905.  
  1906.       }
  1907.     else
  1908.       {
  1909.       address = ALL_LOCALS;
  1910.  
  1911.       }
  1912.  
  1913.     }
  1914.   else
  1915.     {
  1916.     if (!roomBuf.rbflags.SHARED)
  1917.       {
  1918.       mPrintf("Sorry, this is not a network room\n ");
  1919.       return FALSE;
  1920.  
  1921.       }
  1922.     address = R_SH_MARK;
  1923.     strCpy(msgBuf.mboname, cfg.codeBuf + cfg.nodeName);
  1924.     strCpy(msgBuf.mbdomain, cfg.codeBuf + cfg.nodeDomain);
  1925.  
  1926.     }
  1927.   strCpy(msgBuf.mbaddr, address);
  1928.   return TRUE;
  1929.  
  1930.   }
  1931. /*
  1932. * killConnection()
  1933. *
  1934. * Zaps carrier for network.
  1935. */
  1936. void killConnection()
  1937.   {
  1938.   HangUp(TRUE);
  1939.   modStat = haveCarrier = FALSE;
  1940.   while (MIReady()) inp();    /* Clear buffer of garbage */
  1941.  
  1942.   }
  1943. /*
  1944. * setPoll()
  1945. *
  1946. * This allows us to make sure we don't poll hosts too often during a net
  1947. * session.
  1948. */
  1949. void setPoll()
  1950.   {
  1951.   int rover;
  1952.   pollCall = GetDynamic(cfg.netSize);
  1953.   for (rover = 0; rover < cfg.netSize; rover++)
  1954.     {
  1955.     pollCall[rover] = 1;
  1956.  
  1957.     }
  1958.  
  1959.   }
  1960. /*
  1961. * makeCall()
  1962. *
  1963. * This handles the actual task of dialing the modem.
  1964. */
  1965. int makeCall(char EchoErr, MenuId id)
  1966.   {
  1967.   char  call[80];
  1968.   label blip1;
  1969.   int   bufc, result;
  1970.   char  buf[30], c, viable;
  1971.   char  ourArea[4], targetArea[4];
  1972.   while (MIReady()) inp();
  1973.   AreaCode(netBuf.netId, targetArea);
  1974.   AreaCode(cfg.nodeId + cfg.codeBuf, ourArea);
  1975.   if (!netBuf.nbflags.ExternalDialer)
  1976.     {
  1977.     setNetCallBaud(netBuf.baudCode, "makeCall");
  1978.     normId(netBuf.netId, blip1);
  1979.     strCpy(call, cfg.codeBuf + cfg.DialPrefixes[minimum(netBuf.baudCode, cfg.sysBaud)]);
  1980.     if (strLen(netBuf.access) != 0)
  1981.       {
  1982.       /* don't need to check extdial*/
  1983.       strCat(call, netBuf.access);
  1984.  
  1985.       }
  1986.     else if (!netBuf.nbflags.local)
  1987.       {
  1988.       strCat(call, "1");
  1989.       /* LD within same area code? (courtesy farokh irani) */
  1990.       if (strCmp(targetArea, ourArea) == SAMESTRING)
  1991.       strCat(call, blip1 + 5);
  1992.       else
  1993.       strCat(call, blip1 + 2);
  1994.  
  1995.       }
  1996.     else
  1997.       {
  1998.       /* local but different area codes?  (e.g., NYC) */
  1999.       /* again courtesy farokh irani */
  2000.       if (strCmp(targetArea, ourArea) != SAMESTRING)
  2001.       strCat(call, blip1 + 2);
  2002.       else
  2003.       strCat(call, blip1 + 5);
  2004.  
  2005.       }
  2006.     strCat(call, cfg.codeBuf + cfg.netSuffix);
  2007.     switch (RottenDial(call))
  2008.       {
  2009.       case FALSE: moPuts(call); break;
  2010.       case TRUE:  break;
  2011.       case ERROR: return FALSE;
  2012.  
  2013.       }
  2014.     for (startTimer(WORK_TIMER), bufc = 0, viable = TRUE;
  2015.     chkTimeSince(WORK_TIMER) < ((netBuf.nbflags.local) ? 40l : LD_Delay)
  2016.     && viable;)
  2017.       {
  2018.       if (gotCarrier()) break;
  2019.       /* Parse incoming string from modem -- call progress detection */
  2020.       if (KBReady()) viable = FALSE;
  2021.       if (MIReady())
  2022.         {
  2023.         if ((c = inp()) == '\r')
  2024.           {
  2025.           buf[bufc] = 0;
  2026.           switch ((result = ResultVal(buf)))
  2027.             {
  2028.             case R_NODIAL:
  2029.             case R_NOCARR:
  2030.             case R_BUSY:
  2031.             if( logNetResults )
  2032.               {
  2033.               if (EchoErr ) splitF(netLog, "(%s) ", buf);
  2034.               else SysopPrintf(id, "\n%s", buf);
  2035.               };
  2036.             viable = FALSE; break;
  2037.             case R_300:
  2038.             case R_1200:
  2039.             case R_2400:
  2040.             case R_4800:
  2041.             case R_9600:
  2042.             case R_14400:
  2043.             case R_19200:
  2044.             if ((minimum(netBuf.baudCode, cfg.sysBaud)) != result)
  2045.               {
  2046.               setNetCallBaud(result,"makeCall");
  2047.               if( logNetResults )splitF(netLog, "(Mismatch: %s, adjusting.)\n", buf);
  2048.  
  2049.               }
  2050.             break;
  2051.  
  2052.             }
  2053.           bufc = 0;
  2054.  
  2055.           }
  2056.         else
  2057.           {
  2058.           if (bufc > 28) bufc = 0;
  2059.           else if (c != '\n')
  2060.             {
  2061.             buf[bufc++] = c;
  2062.  
  2063.             }
  2064.  
  2065.           }
  2066.  
  2067.         }
  2068.       if( viable ) BeNice(INUSE_PAUSE);  /* give up some CPU time */
  2069.  
  2070.       }
  2071.     if (gotCarrier())
  2072.     return TRUE;
  2073.  
  2074.     }
  2075.   else
  2076.     {
  2077.     return DialExternal(&netBuf);
  2078.  
  2079.     }
  2080.   return FALSE;
  2081.  
  2082.   }
  2083. void ExplainNeed(int i, MULTI_NET_DATA x)
  2084.   {
  2085.   char c0,c1,c2;
  2086.   if (!cfg.BoolFlags.debug) return;
  2087.   c0 = netTab[i].ntShort[0];
  2088.   if( !isprint(c0))c0 = ' ';
  2089.   c1 = netTab[i].ntShort[1];
  2090.   c2 = netTab[i].ntShort[2];
  2091.   if( !isprint(c0))c0 = ' ';
  2092.   if( !isprint(c1))c1 = ' ';
  2093.   if( !isprint(c2))c2 = ' ';
  2094.   splitF(netLog," Networking with:( %c%c%c ) \n",c0,c1,c2);
  2095.   splitF(netLog, "slot %d%sin use is%sspine we are%sa spine \n",
  2096.   i, netTab[i].ntflags.in_use      ? " ":" not ",
  2097.   netTab[i].ntflags.is_spine       ? " ":" not ",
  2098.   netTab[i].ntflags.spine          ? " ":" not ");
  2099.   splitF(netLog, " MN%ld has%smail\n",  netTab[i].ntMemberNets & x,
  2100.   netTab[i].ntflags.normal_mail ? " ":" no ");
  2101.   splitF(netLog, "%sfile requests %ssend requests has%srooms to share\n",
  2102.   netTab[i].ntflags.room_files ? " ":" no ",
  2103.   netTab[i].ntflags.send_files ? " ":" no ",
  2104.   roomsShared(i) ? " ":" no ");
  2105.   splitF(netLog, " Domain Flags:%d has%srouted for %s mode \n",
  2106.   DomainFlags[i],
  2107.   netTab[i].ntflags.HasRouted ? " ":" no ",
  2108.   (inNet == NON_NET)    ? "NON_NET":
  2109.   (inNet == NORMAL_NET) ? "NORMAL_NET" :
  2110.   (inNet == ANYTIME_NET)? "ANYTIME_NET" :
  2111.   (inNet == UNTIL_NET)  ? "UNTIL_NET": "UNKNOWN");
  2112.  
  2113.   }
  2114. #define SpineSet(i) (netTab[i].ntflags.is_spine && !(netTab[i].ntMemberNets & PRIORITY_MAIL))
  2115. /*
  2116. * needToCall()
  2117. *
  2118. * This is responsible for checking to see if we need to call this system.
  2119. * Basically, here's what the rules are:
  2120. *
  2121. * Is this account in use?
  2122. * Is this account on one of the eligible net ('x' parameter)?
  2123. * Is this account not a spine and not an OtherNet system?
  2124. *
  2125. * If this system is a spine and we're not doing an anytime-net session
  2126. * and we haven't had a successful connection yet then call.
  2127. *
  2128. * If this system has normal mail, room file requests, send file requests,
  2129. * rooms that need to share (outgoing messages), domain mail outgoing, mail
  2130. * routing and hasn't been connected with yet, then call.
  2131. *
  2132. * I'm not entirely sure what the reference to Priority Mail signifies in
  2133. * this mess.
  2134. */
  2135. int needToCall(int i, MULTI_NET_DATA x)
  2136.   {
  2137.   /* first check for permission to call   */
  2138.   if (cfg.BoolFlags.debug)
  2139.     {
  2140.     splitF(netLog, "needToCall(%d, %08.8lX)\n",i,x);
  2141.     splitF(netLog, "netTab[%d].ntflags.in_use  = %d\n",i,netTab[i].ntflags.in_use);
  2142.     splitF(netLog, "netTab[%d].ntMemberNets    = %08.8lX\n",i,netTab[i].ntMemberNets);
  2143.     splitF(netLog, "netTab[%d].ntflags.is_spine= %s\n",i, (netTab[i].ntflags.is_spine ? "Yes":"No") );
  2144.     splitF(netLog, "netTab[%d].ntflags.spine   = %s\n",i, (netTab[i].ntflags.spine ? "Yes" : "No") );
  2145.     splitF(netLog, "inNet = ");
  2146.     switch (inNet)
  2147.       {
  2148.       case     NON_NET: splitF(netLog, "NON_NET\n");break;
  2149.       case  NORMAL_NET: splitF(netLog, "NORMAL_NET\n");break;
  2150.       case   UNTIL_NET: splitF(netLog, "UNTIL_NET\n");break;
  2151.       case ANYTIME_NET: splitF(netLog, "ANYTIME_NET\n");break;
  2152.       default:         splitF(netLog, "UNKNOWN=%d\n",inNet);
  2153.       };
  2154.     splitF(netLog, "netTab[%d].ntflags.in_use = %d\n",i,netTab[i].ntflags.in_use);
  2155.     };
  2156.   if (netTab[i].ntflags.in_use &&     /* account in use   */
  2157.   (netTab[i].ntMemberNets & x) &&  /* system is member of net      */
  2158.   !SpineSet(i) &&
  2159.   !netTab[i].ntflags.OtherNet)
  2160.     {
  2161.     /* system not OtherNet    */
  2162.     /* check for requirement to call  */
  2163.     if (netTab[i].ntflags.spine &&
  2164.     !(netTab[i].ntMemberNets & PRIORITY_MAIL) &&
  2165.     (inNet == NON_NET || ((inNet == NORMAL_NET || inNet == UNTIL_NET) &&
  2166.     pollCall[i] == 1)))
  2167.     return TRUE;
  2168.     /* now check for need to call     */
  2169.     if (cfg.BoolFlags.debug)
  2170.       {
  2171.       splitF(netLog,"netTab[%d].ntflags.normal_mail=%s\n",i, netTab[i].ntflags.normal_mail? "yes" :"no");
  2172.       splitF(netLog,"netTab[%d].ntflags.room_files =%s\n",i, netTab[i].ntflags.room_files ? "yes" :"no");
  2173.       splitF(netLog,"netTab[%d].ntflags.send_files =%s\n",i, netTab[i].ntflags.send_files ? "yes" :"no");
  2174.       splitF(netLog,"netTab[%d].ntflags.HasRouted  =%s\n",i, netTab[i].ntflags.HasRouted  ? "yes" :"no");
  2175.       splitF(netLog, "DomainFlags[%d]              =%s\n",i, DomainFlags[i]               ? "yes" :"no");
  2176.  
  2177.       }
  2178.     if (netTab[i].ntflags.normal_mail ||  /* normal outgoing mail?*/
  2179.     netTab[i].ntflags.room_files || /* request files ?  */
  2180.     netTab[i].ntflags.send_files || /* send files ?   */
  2181.     roomsShared(i) ||     /* rooms to share?  */
  2182.     DomainFlags[i] ||     /* domain mail to send? */
  2183.     (netTab[i].ntflags.HasRouted &&
  2184.     (inNet == NON_NET ||
  2185.     ((inNet == NORMAL_NET || inNet == ANYTIME_NET ||
  2186.     inNet == UNTIL_NET) &&
  2187.     pollCall[i] == 1))))
  2188.     return TRUE;
  2189.  
  2190.     }
  2191.   return FALSE;
  2192.  
  2193.   }
  2194. /*
  2195. * AnyCallsNeeded()
  2196. *
  2197. * Do we need to make any calls 'tall?
  2198. */
  2199. char AnyCallsNeeded(MULTI_NET_DATA whichNets)
  2200.   {
  2201.   int searcher;
  2202.   for (searcher = 0; searcher < cfg.netSize; searcher++)
  2203.   if (needToCall(searcher, whichNets)) return TRUE;
  2204.   return FALSE;
  2205.  
  2206.   }
  2207. /*
  2208. * ReqNodeName()
  2209. *
  2210. * This function is a general request for node name from user.  It supports
  2211. * various options for prompting or not prompting for the name, allowing the
  2212. * input of '&L', allow display of nodelists, etc. (see the code).  The
  2213. * function will validate the choice, query again if appropriate, handle
  2214. * domains, and do a getNet of the node if necessary.
  2215. */
  2216. char ReqNodeName(char *prompt, label target, label domain, char WideSpecValid,
  2217. char Once, char Ask, char Display, char SysopMenu,
  2218. NetBuffer *nBuf)
  2219.   {
  2220.   extern char *ALL_LOCALS;
  2221.   char sysname[2 * NAMESIZE], dup, work[2 * NAMESIZE];
  2222.   int  slot;
  2223.   do
  2224.     {
  2225.     slot = ERROR;
  2226.     if (domain != NULL) domain[0] = 0;
  2227.     /* Allows function to act as validator only */
  2228.     if (Ask)
  2229.       {
  2230.       getString(prompt, sysname, 2 * NAMESIZE, QUEST_SPECIAL);
  2231.  
  2232.       }
  2233.     else strCpy(sysname, target);
  2234.     NormStr(sysname);
  2235.     /* Empty line implies operation abort. */
  2236.     if (strLen(sysname) == 0)
  2237.       {
  2238.       strCpy(target, sysname);
  2239.       return FALSE;
  2240.  
  2241.       }
  2242.     /* If "&L" entered and is acceptable ... */
  2243.     if (WideSpecValid && strCmpU(sysname, ALL_LOCALS) == SAMESTRING)
  2244.       {
  2245.       strCpy(target, sysname);
  2246.       return TRUE;
  2247.  
  2248.       }
  2249.     /* Questioning frown */
  2250.     if (sysname[0] == '?')
  2251.       {
  2252.       writeNet(Display, FALSE);   /* write out available nets */
  2253.       if (WideSpecValid)
  2254.       mPrintf("'&L' == Local Systems Announcement\n ");
  2255.  
  2256.       }
  2257.     /* finally, must be real system name so seeeeearch for it! */
  2258.     else if ((slot = searchNameNet(sysname, nBuf)) != ERROR)
  2259.       {
  2260.       strCpy(target, nBuf->netName);  /* aesthetics */
  2261.       if (nBuf->nbflags.local || nBuf->nbflags.RouteLock)
  2262.         {
  2263.         return TRUE;    /* Yup */
  2264.  
  2265.         }
  2266.  
  2267.       }
  2268.     if (domain != NULL && SystemInSecondary(sysname, domain, &dup))
  2269.       {
  2270.       if (dup)
  2271.         {
  2272.         /* oops */
  2273.         if (slot != ERROR) return TRUE;
  2274.         /* do it as a double if, not claused */
  2275.         if (Ask)
  2276.           Output_Citadel_Message("DUPDOM", (long)sysname, NULL, NULL);
  2277.  
  2278.         }
  2279.       else
  2280.         {
  2281.         strCpy(target, sysname);  /* aesthetics */
  2282.         return TRUE;
  2283.  
  2284.         }
  2285.  
  2286.       }
  2287.     if (slot != ERROR) return TRUE;
  2288.     if (sysname[0] != '?')
  2289.       {
  2290.       sPrintf(work, "%s not listed.\n", sysname); /* Nope */
  2291.       if (SysopMenu) SysopError(NO_MENU, work);
  2292.       else     mPrintf(work);
  2293.  
  2294.       }
  2295.  
  2296.     }
  2297.   while (!Once && Ask); /* This controls if we ask repeatedly or only once */
  2298.   return FALSE;       /* And if we get here, we definitely are a failure */
  2299.  
  2300.   }
  2301. /*
  2302. * NetValidate()
  2303. *
  2304. * This will return TRUE if net privs are go, FALSE otherwise.
  2305. */
  2306. char NetValidate(char talk)
  2307.   {
  2308.   if (!cfg.BoolFlags.netParticipant)
  2309.     {
  2310.     if (talk)
  2311.       Output_Citadel_Message("NTPTNT",NULL, NULL, NULL);
  2312.     return FALSE;
  2313.  
  2314.     }
  2315.   if( loggedIn && logBuf.lbflags.NET_PRIVS ) return TRUE;
  2316.   if( loggedIn && roomBuf.rbflags.AUTO_NET ) return TRUE;
  2317.   if( loggedIn && roomBuf.rbflags.ALL_NET  ) return TRUE;
  2318.   if (talk)
  2319.     Output_Citadel_Message("NTPTNT",NULL, NULL, NULL);
  2320.   return FALSE;
  2321.   }
  2322. /*
  2323. * FindRouteIndex()
  2324. *
  2325. * This will find the next route filename in sequence.
  2326. */
  2327. int FindRouteIndex(int slot)
  2328.   {
  2329.   label temp;
  2330.   SYS_FILE newfn;
  2331.   sPrintf(temp, "R%d", slot);
  2332.   if (cfg.BoolFlags.debug) splitF(netLog,"FindRouteIndex(%d)\n",slot);
  2333.   makeSysName(newfn, temp, &cfg.netArea);
  2334.   return FindNextFile(newfn);
  2335.  
  2336.   }
  2337. typedef struct
  2338.   {
  2339.   int count;
  2340.   char *str;
  2341.  
  2342.   }
  2343. SR_Arg;
  2344. /*
  2345. * ParticipatingNodes()
  2346. *
  2347. * This function prepares a string indicating who shares the current room with
  2348. * us.
  2349. */
  2350. void ParticipatingNodes(char *target)
  2351.   {
  2352.   int    node;
  2353.   SR_Arg arg;
  2354.   char   *c;
  2355.   int ShowSharedRoomName(SharedRoom *room, int system, int index,
  2356.   int roomslot, void *arg);
  2357.   sPrintf(lbyte(target), ". This room is shared with: ");
  2358.   arg.count = 0;
  2359.   arg.str   = target;
  2360.   for (node = 0; node < cfg.netSize; node++)
  2361.   EachSharedRoom(node, ShowSharedRoomName, NULL, &arg);
  2362.   if (arg.count)
  2363.     {
  2364.     /* this eliminates the trailing comma */
  2365.     c = lbyte(target);
  2366.     c -= 2;
  2367.     *c = 0;
  2368.  
  2369.     }
  2370.  
  2371.   }
  2372. /*
  2373. * ShowSharedRoomName()
  2374. *
  2375. * This appends the name of this shared room to a string.
  2376. */
  2377. int ShowSharedRoomName(SharedRoom *room, int system, int index, int roomslot,
  2378. void *d)
  2379.   {
  2380.   SR_Arg *arg;
  2381.   char *name;
  2382.   char commnd, *s1, *s2, *s3, doit;
  2383.   arg = d;
  2384.   if (roomslot == thisRoom)
  2385.     {
  2386.     getNet(system, &netBuf);
  2387.     arg->count++;
  2388.     Addressing(system, index, &commnd, &s1, &s2, &s3, &name, &doit);
  2389.     sPrintf(lbyte(arg->str), "%s (%s), ", netBuf.netName, name);
  2390.     return ERROR;
  2391.  
  2392.     }
  2393.   return TRUE;
  2394.  
  2395.   }
  2396. /*
  2397. * AreaCode()
  2398. *
  2399. * This function extracts the area code from the node id.
  2400. */
  2401. void AreaCode(char *Id, char *Target)
  2402.   {
  2403.   int i, j;
  2404.   for (i = j = 0; j < 3 && Id[i]; i++)
  2405.   if (isdigit(Id[i]))
  2406.   Target[j++] = Id[i];
  2407.   Target[j] = 0;
  2408.  
  2409.   }
  2410. /*
  2411. * NetInit()
  2412. *
  2413. * This function does network initialization: Cache handling, network recovery
  2414. * (in case of crash during netting), etc...
  2415. */
  2416. void NetInit()
  2417.   {
  2418.   int rover;
  2419.   char buf[2*NAMESIZE];
  2420.   SpecialMessage("Network Initialization");
  2421.   MakeNetCache(buf);
  2422.   if (access(buf, 0) != 0) mkdir(buf);
  2423.   VirtInit();
  2424.   VortexInit();
  2425.   /* we never need do this again */
  2426.   normId(cfg.codeBuf + cfg.nodeId, HomeId);
  2427.   DomainInit(TRUE);
  2428.   for (rover = 0; rover < cfg.netSize; rover++)
  2429.   if (netTab[rover].ntMemberNets & PRIORITY_MAIL) PriorityMail++;
  2430.   RecoverNetwork();
  2431.   SpecialMessage("");
  2432.  
  2433.   }
  2434. /*
  2435. * MakeNetted()
  2436. *
  2437. * This function will make a message into a net message.  This is userland
  2438. * code called when an aide wants to make a non-netted message into a netted
  2439. * message.
  2440. */
  2441. char MakeNetted(int m)
  2442.   {
  2443.   if (findMessage(roomBuf.msg[m].rbmsgLoc, roomBuf.msg[m].rbmsgNo, TRUE))
  2444.     {
  2445.     getMsgStr(getMsgChar, msgBuf.mbtext, MAXTEXT);  /* get balance */
  2446.     strCpy(msgBuf.mboname, cfg.codeBuf + cfg.nodeName);
  2447.     strCpy(msgBuf.mbdomain, cfg.codeBuf + cfg.nodeDomain);
  2448.     strCpy(msgBuf.mbaddr, R_SH_MARK);
  2449.     DelMsg(TRUE, m);
  2450.     putMessage(NULL);
  2451.     return NETTED;
  2452.  
  2453.     }
  2454.   return NO_CHANGE;
  2455.  
  2456.   }
  2457. /*
  2458. * freeUNS()
  2459. *
  2460. * This function is purportedly a free function for a list.  In actuality,
  2461. * it also runs a net session for each.
  2462. */
  2463. void freeUNS(TwoNumbers *netdata)
  2464.   {
  2465.   int yr, dy, hr, mn, mon, secs, milli;
  2466.   if (!onLine())
  2467.     {
  2468.     getRawDate(&yr, &mon, &dy, &hr, &mn, &secs, &milli);
  2469.     netController((hr * 60) + mn, (int) netdata->second,
  2470.     (1l << (netdata->first - 1)), UNTIL_NET, 0);
  2471.  
  2472.     }
  2473.   free(netdata);
  2474.  
  2475.   }
  2476. /*
  2477. * GetCompression()
  2478. *
  2479. * Gets the compression value.
  2480. */
  2481. int GetCompression(int system)
  2482.   {
  2483.   if (netTab[system].ntflags.Arc) return ARC_COMP;
  2484.   if (netTab[system].ntflags.Zoo) return ZOO_COMP;
  2485.   if (netTab[system].ntflags.Lzh) return LZH_COMP;
  2486.   return LHA_COMP;
  2487.  
  2488.   }
  2489. /*
  2490. * HasOutgoing()
  2491. *
  2492. * This function checks to see if the given room as specified by the system,
  2493. * index pair has outgoing messages in either cache or message form.
  2494. *
  2495. * NB: This code may not be OK.
  2496. */
  2497. char HasOutgoing(int system, int index)
  2498.   {
  2499.   if (GetFA(netTab[system].netTRooms[index].mode)) return TRUE;
  2500.   if (roomTab[netTabRoomSlot(system, index)].rtlastMessage >
  2501.   netTab[system].netTRooms[index].lastMess) return TRUE;
  2502.   return FALSE;
  2503.  
  2504.   }
  2505.